//
// File peer.h
//
// This file defines the four public methods of class Peer, together 
// with associated helper classes and constants
//

// Various limits

#ifndef PEER_H
#define PEER_H

#include <string>
#include "Common.h"
#include "peerInfo.h"
#include "FileSystem.h"
#include "Jobs.h"

// Peer and Status are the classes we really care about
// Peers is a container; feel free to do a different container

class Peer {
    // This is the formal interface and you should follow it
public:
    Peer(string ip, int port, string deviceType);
    ~Peer();

    // must be on network...
    int create(string filename);
    int deleteFile(string filename);

    int tag(string filename);
    int tag(string filename, int version);

    int save(string filename);
    int save(string filename, int version);

    int list();
    int join();     // Note that we should have the peer list, so it is not needed as a parameter
    int leave();

    int modify(string filename);
    int modify(string filename, int version);

    int openFile(string filename);
    int openFile(string filename, int version);

    int closeFile(string filename);
    int closeFile(string filename, int version);

    enum Message { JOIN, LEAVE, QUERYSTATUS, NEWFILE, REPLYSTATUS,
                    EXITLISTENER, SYSREQUEST, SAVESUCCESS, TAGSUCCESS, REQUESTFILE, REQUESTUPDATE, DELETEDFILE,
                    SAVEFILE, TAGFILE, NEWMODIFIED, JOINANDQUERY, QUERYVFS, REPLYVFS, NAK, QUERYTRANSFERFILES, REPLYTRANSFERFILES, TRANSFERFILE };

    int test();


private:
    peerInfo *localInfo;
    peerInfo *_peers[maxPeers];
    int _numPeers;

    string _peerList; // maybe this should be passed in constructor...

    FileSystem *VFS;
    queue<Job *> jobs;

    sem_t job_queue_count;
    pthread_mutex_t job_queue_mutex;
    pthread_mutex_t VFS_mutex;

// thread related initialization stuff
    vector<pthread_t *> _workerContext;
    pthread_t _listenerContext;
    pthread_t _updaterContext;

    bool updater_terminate_flag;

    bool startListenerThread();
    bool startWorkerThreads();
    bool startUpdaterThread();

    bool terminateUpdaterThread();

    int workerImplementation();
    int listenerImplementation();
    int updaterImplementation();

    static void *listener(void *This);
    static void *worker(void *This);
    static void *updater(void *This);

// message related helper functions
    int process_message(int client_sock, char *buf, int bufLen);
    int create_message(Peer::Message type, void *msgParams, char *mail, int &length);

// network information helper functions
    pthread_mutex_t network_info_mutex;

    int processPeerList(string peerList);
    int peerJoin(string ip, int port, string deviceType);
    int peerLeave(string ip, int port);
    int resetNetworkInfo();

// broadcast helper functions
    int blockingBroadcast(char *mail, int length);
    int nonblockingBroadcast(char *mail, int length);
    int blockingSendToAny(char *mail, int length);
    int nonblockingSend(string ip, int port, char *mail, int length);
    int blockingSend(string ip, int port, char *mail, int length);

// job queue helpers
    int pushJob(Job *job);
    int process_job(Job *job);

// clock functions
    int getSystemTime();
};

#endif
